﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;

namespace HardwareUtils
{
    public class UsbEventWatcher : IDisposable
    {
        private ManagementEventWatcher _managementEventWatcher;
        private readonly EventArrivedEventHandler _managementEventWatcherOnEventArrived;
        private Action<string, bool> ConnectHandler;

        public UsbEventWatcher(EventArrivedEventHandler onEventArrived, int intervalMillis = 1000)
        {
            WqlEventQuery _q = new WqlEventQuery("__InstanceOperationEvent", "TargetInstance ISA 'Win32_USBControllerDevice' ");
            _q.WithinInterval = TimeSpan.FromMilliseconds(intervalMillis);
            this._managementEventWatcher = new ManagementEventWatcher(_q);
            this._managementEventWatcherOnEventArrived = onEventArrived;
            this._managementEventWatcher.EventArrived += this._managementEventWatcherOnEventArrived;
            this._managementEventWatcher.Start();
        }

        public UsbEventWatcher(Action<string, bool> connectHandler, int intervalMillis = 1000)
        {
            this.ConnectHandler = connectHandler;
            WqlEventQuery _q = new WqlEventQuery("__InstanceOperationEvent", "TargetInstance ISA 'Win32_USBControllerDevice' ");
            _q.WithinInterval = TimeSpan.FromMilliseconds(intervalMillis);
            this._managementEventWatcher = new ManagementEventWatcher(_q);
            this._managementEventWatcherOnEventArrived = this.HandleDeviceChange;
            this._managementEventWatcher.EventArrived += this._managementEventWatcherOnEventArrived;
            this._managementEventWatcher.Start();
        }


        private void HandleDeviceChange(object sender, EventArrivedEventArgs e)
        {
            ManagementBaseObject _o = e.NewEvent["TargetInstance"] as ManagementBaseObject;

            if (_o != null)
            {
                using (ManagementObject mo = new ManagementObject(_o["Dependent"].ToString()))
                {
                    if (mo != null)
                    {
                        try
                        {
                            if (mo.GetPropertyValue("DeviceID").ToString() != string.Empty)
                            {
                                ConnectHandler(mo.Path.ToString(), true);
                            }
                        }
                        catch (ManagementException ex)
                        {
                            string path = _o.Properties["Dependent"].Value.ToString();
                            ConnectHandler(path, false);
                        }
                    }
                }
            }
        }


        #region Implementation of IDisposable
        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        /// <filterpriority>2</filterpriority>
        public void Dispose()
        {
            this._managementEventWatcher.Stop();
            this._managementEventWatcher.EventArrived -= this._managementEventWatcherOnEventArrived;
            this._managementEventWatcher.Dispose();
            this._managementEventWatcher = null;
        }
        #endregion
    }
}
